/**
 * @file FileList.h
 * @author Piotr Jasiun
 *
 * Nagłówki klas odpowiedzialnych za odbługę pliku konfiguracyjnego zawierającego informacje o położeniu żądanych plików oraz klasy udostępniającej żądany fragment pliku.
 */

#ifndef FILELIST_H_
#define FILELIST_H_

#include <iostream>
#include <string>
#include <list>
#include <sstream>
#include "structures.h"

namespace tftp_server
{
/**
 * @class File
 * Klasa opisująca plik którego fragment jest zwracany.
 */
class File
{
protected:
	std::string fileName; ///nazwa pliku; pusta nazwa ozacza, że plik nie został znaleziony
public:
	/**
	 * Wirtualny destruktor klasy.
	 */
	virtual ~File () {}

	/**
	 * Metoda zwracająca rządany fragment pliku w odpowiednim formacie. Czysto wirtualna klasa bazowa.
	 * @param form - od którego bajtu zaczyna się fragment
	 * @param size - ile bajtów zwrócić
	 */
	virtual int getFragment(int from, int size, char * content) = 0;

	/**
	 * Metoda zwracająca nazwę pliku.
	 */
	string getRealFileName()	{return fileName;};

	/**
	 * Metoda zwracająca informacje o tym, czy dany plik nie jest pustym plikiem i powinna być wywołana przed próbą pobrania fragmentu. Pusty plik jest zwracany w sytuacji gdy nie udało się znaleźć poszukiwanego pliku.
	 */
	bool isNull(){return (fileName == "");};

	/**
	 * Metoda zwracająca rozmiar pliku.
	 */
	int getSize();

	/**
	 * Metoda zwracająca informacje o tym, czy dany plik rzeczywiście istnieje.
	 */
	bool isExist();

	/**
	 * Metoda zwracająca informacje o tym, czy dany plik jest dostępny (czy program ma odpowiednie uprawnienia)
	 */
	bool isAccessible ();
};

/**
 * @class BinFile
 * Klasa opakowująca plik odczytywany w trybie binarnym. Przetrzymuje tylko nazwę pliku i odczytuje z pliku tylko żądany fragment. Informacja o nie znalezieniu pliku jest zracana w postaci pustego pliku binarnego.
 */
class BinFile: public File
{
public:

	/**
	 * Konstruktor bezargumentowy.
	 */
	BinFile() {File::fileName="";}

	/**
	 * Konstruktor klasy.
	 * @param _fileName - nazwa pliku
	 */
	BinFile (std::string _fileName) {File::fileName=_fileName;}

	/**
	 * Metoda zwracająca rządany fragment pliku w odpowiednim formacie.
	 * @param form - od którego bajtu zaczyna się fragment
	 * @param size - ile bajtów zwrócić
	 */
	virtual int getFragment(int from, int size, char * content);

};

/**
 * @class AsciiFile
 * Klasa opakowująca plik odczytywany w trybie ASCII. Konstruktor alokuje pamięć, ładuje do pamięci cały plik i dokonuje od razu odpowiednich przekształceń. Nie nadaje się do przetrzymywania dużych plików.
 */
class AsciiFile: public File
{
private:
	char * fileContents; /// zawarość pliku
	int transformatedFileSize; /// rozmiar pliku po transformacji ASCII.
public:
	/**
	 * Konstruktor klasy.
	 * @param _fileName - nazwa pliku
	 */
	AsciiFile (std::string _fileName);

	/**
	 * Destruktor klasy
	 */
	virtual ~AsciiFile ()	{delete(fileContents);}

	/**
	 * Metoda zwracająca rządany fragment pliku w odpowiednim formacie.
	 * @param form - od którego bajtu zaczyna się fragment
	 * @param size - ile bajtów zwrócić
	 */
	virtual int getFragment(int from, int size, char * content);
};

/**
 * Struktura zawierająca przypisanie nazwy żądanego pliku i adresu IP do realnej lokalizacji pliku.
 */
struct FileIP {
	IP FileIP; /// adres IP
	std::string fileName; /// nazwa żądanego pliku
	std::string realFile; /// realna lokalizacja pliku
};

/**
 * Struktura zawierająca przypisanie nazwy żądanego pliku i adresu MAC do realnej lokalizacji pliku.
 */
struct FileMAC {
	MAC FileMAC; /// adres MAC
	std::string fileName; /// nazwa żądanego pliku
	std::string realFile; /// realna lokalizacja pliku
};

/**
 * @class FileList
 * Klasa obsługująca plik konfiguracyjny i zwracający dla danego IP lub MAC odpowiedni plik.
 */
class FileList
{
private:
	std::list<FileMAC> MAClist; /// lista dowiązań nazwy żądanego pliku i adresu MAC do realnej lokalizacji pliku. Wraz z IPlist stanowi kontener przechowujący całą konfiguracę.
	std::list<FileIP> IPlist; /// lista dowiązań nazwy żądanego pliku i adresu IP do realnej lokalizacji pliku. Wraz z MAClist stanowi kontener przechowujący całą konfiguracę.

	FileList(){}
	FileList(const FileList&);
	FileList& operator=(const FileList&);

public:
	/// Inicjalizacja statycznego obiektu.
	static FileList& getInstance()
	{
		static FileList instance;
		return instance;
	};

	/**
	 * Wczytanie odpowiedniego pilku konfiguracyjnego.
	 * @param FileName - nFileazwa pliku konfiguracyjnego
	 * @return - funkcja zwraca informacje o tym czy udało się saładować plik konfiguracyjny.
	 */
	bool setConfigFile(std::string FileName);

	/**
	 * Wyświetlenie aktualnie załadowanej konfiguracji na ektran.
	 */
	void show();

	/**
	 * Pobranie pliku dla kompretnego komputera.
	 * Metoda przeszkuje plik konfiguracyjny i zwraca pierwszy plik dla którego zgadza się IP lub MAC.
	 * @param ip - adres ip komputera, który rząda pliku
	 * @param mac - adres mac komputera, który rząda pliku; w przypadku braku adresu należy podać adres zerowy lub inny co do którego jest pewność, że żaden z komputerów nie ma takiego
	 * @param fileName - nazwa żądanego pliku
	 * @param type - format w jakim będą pobierane dane z pliku ('a' = ASCII, 'b' - binarny)
	 */
	File* getFile(IP ip, MAC mac, std::string fileName, char type);

private:
	/**
	 * Metoda pomocnicza torząca odpowiedni obiekt BinFile lub AsciiFile na podstawie żądanego typu i rzutująca go na klasę bazową.
	 * @param fileName - nazwa żądanego pliku
	 * @param type - format w jakim będą pobierane dane z pliku ('a' = ASCII, 'b' - binarny)
	 */
	File * selectType(std::string fileName, char type);
};

}
#endif /* FILE_H_ */
